#include <time.h>
#include <string.h>
#include <stddef.h>

#include "comm_pipe.h"
#include "../lib/utils/utils.h"

comm_pipe::comm_pipe()
	: mFIFO_PATH(NULL),
	mFIFO_PATH_RET(NULL)
{	
	
}

comm_pipe::~comm_pipe()
{
	if(mFIFO_PATH != NULL){
		unlink(mFIFO_PATH);
		free(mFIFO_PATH);
	}

	if(mFIFO_PATH != NULL){
		unlink(mFIFO_PATH_RET);
		free(mFIFO_PATH_RET);
	}
}

int comm_pipe::open(void * comm_para)
{
	int err;

	mFIFO_PATH = (char *)malloc(strlen((char *)comm_para) + 1);
	mFIFO_PATH_RET = (char *)malloc(strlen((char *)comm_para) + strlen("Ret")+ 1);

	strcpy(mFIFO_PATH, (char *)comm_para);
	strcpy(mFIFO_PATH_RET, mFIFO_PATH);
	strncat(mFIFO_PATH_RET, "Ret", sizeof(mFIFO_PATH_RET) - 1);

	unlink(mFIFO_PATH);
	mkfifo(mFIFO_PATH, 0777);

	unlink(mFIFO_PATH_RET);
	mkfifo(mFIFO_PATH_RET, 0777);

	mPipeRdHandle = ::open(mFIFO_PATH, O_RDONLY | O_NONBLOCK);
	if (mPipeRdHandle < 0) {
		perror("Open pipe for read error");
		return -1;
	}

	mPipeWrHandle = ::open(mFIFO_PATH_RET, O_RDWR| O_NONBLOCK);
	if (mPipeWrHandle < 0) {
		perror("Open pipe for write error");
		return -1;
	}
	
	err = pthread_create(&mReadThread,NULL,read_thread,(void *)this);
	if(err != 0){
		perror("Create read thread error\n");
		exit(-1);
	}
	
	return 0;
}

int comm_pipe::write(char * p_data, size_t length)
{
	return ::write(mPipeWrHandle,p_data,length);
}

int comm_pipe::read(char * p_data, size_t req_len)
{
	int avail_count = mBuf->get_data_size();
	int req = MIN(avail_count,req_len);
	return mBuf->read_buffer((void *)p_data,req);
}

int comm_pipe::read_a_line(char * p_data, size_t req_len)
{
	char *cur = p_data;
	int i;
	int avail_count = mBuf->get_data_size();
	int req = MIN(avail_count,req_len);
	for(i = 0; i < req; i++,cur++){
		if(mBuf->read_buffer((void *)cur,1) != 1){
			return -1;
		}
		if(*cur == '\n'){
			break;
		}
	}
	return ++i;
}


int comm_pipe::check_line(char *buf)
{
	int ret = -1;
	char *cur = buf;
	while(cur = strstr(cur,"\n")){
		ret = 0;
		sem_post(&mSemCanRead);
		cur++;
	}
	return ret;
}

#if 0
int comm_pipe::check_line(char *buf)
{
	int ret = -1;
	char *cur = buf;
	if(cur = strstr(cur,"\n")){
		ret = 0;
		sem_post(&mSemCanRead);
	}
	return ret;
}
#endif


void comm_pipe::_read_thread()
{	
	char c;
	const int tmp_len = 64;
	int recved_len = 0;
	int recv_len = 0;
	int ret = 0;
	char tmp_buf[tmp_len];
	FD_ZERO(&mRds);
	FD_SET(mPipeRdHandle, &mRds);
	//printf("I am read()\n");
	while(1){		
		ret = select(mPipeRdHandle + 1, &mRds, NULL, NULL, NULL);
		if (ret < 0) {
			perror("select error, time out");
			continue;
		}
		//printf("select OK\n");
		if(FD_ISSET(mPipeRdHandle, &mRds)){
			while(1){
				//printf("Buffer free %d bytes\n",mBuf->get_free_size());			
				recv_len = MIN(tmp_len-1,mBuf->get_free_size());
				//printf("Can get %d bytes\n",recv_len);
				if(recv_len > 0){
					recved_len = ::read(mPipeRdHandle, &tmp_buf, recv_len);
					if(recved_len > 0){
						tmp_buf[recved_len] = '\0';
						mBuf->write_buffer(tmp_buf,recved_len);
						///XXXX: How to make it outside
						check_line(tmp_buf);
						//printf("read: %s,%d\n",tmp_buf,recved_len);	
					}else{
						break;
					}
				}else{					
					perror("Buffer is FULL!\n");
					break;
				}
			}
		}
	}
}


void *comm_pipe::read_thread(void *thread_para)
{
	comm_pipe *me = (comm_pipe *)thread_para;
	me->_read_thread();
	return NULL;
}


int comm_pipe::close()
{
	return 0;
}

int comm_pipe::flush()
{
	return 0;
}
